package com.ddtech.framework.system.rest;

import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import com.ddtech.annotation.AnonymousAccess;
import com.ddtech.config.DataScope;
import com.ddtech.exception.BadRequestException;
import com.ddtech.framework.log.aop.log.Log;
import com.ddtech.framework.log.service.LoginLogService;
import com.ddtech.framework.system.model.SysUser;
import com.ddtech.framework.system.model.vo.UserInfoVo;
import com.ddtech.framework.system.model.vo.UserPassVo;
import com.ddtech.framework.system.service.DeptService;
import com.ddtech.framework.system.service.RoleService;
import com.ddtech.framework.system.service.UserService;
import com.ddtech.framework.system.service.dto.RoleSmallDTO;
import com.ddtech.framework.system.service.dto.UserQueryCriteria;
import com.ddtech.utils.EncryptUtils;
import com.ddtech.utils.PageUtil;
import com.ddtech.utils.SecurityUtils;
import com.ddtech.utils.StringUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotBlank;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author Apache License
 * @date 2018-11-23
 */
@Api(tags = "系统-用户管理")
@RestController
@RequestMapping("api")
public class UserController {

    @Value("${rsa.private_key}")
    private String privateKey;
    @Value("${default.password}")
    private String defaultPwd;

    @Autowired
    private UserService userService;

    @Autowired
    private DataScope dataScope;

    @Autowired
    private DeptService deptService;

    @Autowired
    private LoginLogService loginLogService;

    @Autowired
    private RoleService roleService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Log("查询用户")
    @GetMapping(value = "/users")
    @PreAuthorize("hasAnyRole('ADMIN','USER_ALL','USER_SELECT')")
    public ResponseEntity getUsers(UserQueryCriteria criteria, Pageable pageable) {
        Set<String> deptSet = new HashSet<>();
        Set<String> result = new HashSet<>();
        if (!ObjectUtils.isEmpty(criteria.getDeptId())) {
            deptSet.add(criteria.getDeptId());
            deptSet.addAll(dataScope.getDeptChildren(deptService.findByPid(criteria.getDeptId())));
        }
        // 数据权限
        //Set<String> deptIds = dataScope.getDeptIds();
        Set<String> deptIds=new HashSet<>();
        // 查询条件不为空并且数据权限不为空则取交集
        if (!CollectionUtils.isEmpty(deptIds) && !CollectionUtils.isEmpty(deptSet)) {
            // 取交集
            result.addAll(deptSet);
            result.retainAll(deptIds);
            // 若无交集，则代表无数据权限
            criteria.setDeptIds(result);
            criteria.setId("1");
            if (result.size() == 0) {
                return new ResponseEntity(PageUtil.toPage(null, 0), HttpStatus.OK);
            } else {
                return new ResponseEntity(userService.queryAll(criteria, pageable), HttpStatus.OK);
            }
            // 否则取并集
        } else {
            result.addAll(deptSet);
            result.addAll(deptIds);
            criteria.setDeptIds(result);
            criteria.setId("1");
            return new ResponseEntity(userService.queryAll(criteria, pageable), HttpStatus.OK);
        }
    }

    @Log("新增用户")
    @PostMapping(value = "/users")
    @PreAuthorize("hasAnyRole('ADMIN','USER_ALL','USER_CREATE')")
    public ResponseEntity create(@Validated @RequestBody SysUser resources) {
        checkLevel(resources);
        if(StringUtils.isEmpty(resources.getPassword())){
            // 默认密码
            resources.setPassword(passwordEncoder.encode(defaultPwd.trim()));
        }else{
            resources.setPassword(passwordEncoder.encode(resources.getPassword().trim()));
        }
        return new ResponseEntity(userService.create(resources), HttpStatus.CREATED);
    }

    @Log("修改用户")
    @PutMapping(value = "/users")
    @PreAuthorize("hasAnyRole('ADMIN','USER_ALL','USER_EDIT')")
    public ResponseEntity update(@Validated(SysUser.Update.class) @RequestBody SysUser resources) {
        checkLevel(resources);
        userService.update(resources);
        return new ResponseEntity(HttpStatus.NO_CONTENT);
    }

    @Log("修改个人信息")
    @PostMapping(value = "/updateUserInfo")
    public ResponseEntity updateUserInfo(@RequestBody UserInfoVo userInfoVo) {
        userInfoVo.setUserName(SecurityUtils.getUsername());
        userService.updateUserInfo(userInfoVo);
        return new ResponseEntity(HttpStatus.NO_CONTENT);
    }


    @Log("删除用户")
    @DeleteMapping(value = "/users/{id}")
    @PreAuthorize("hasAnyRole('ADMIN','USER_ALL','USER_DELETE')")
    public ResponseEntity delete(@PathVariable String id) {
        Integer currentLevel = Collections.min(roleService.findByUsers_Id(SecurityUtils.getUserId()).stream().map(RoleSmallDTO::getLevel).collect(Collectors.toList()));
        Integer optLevel = Collections.min(roleService.findByUsers_Id(id).stream().map(RoleSmallDTO::getLevel).collect(Collectors.toList()));

        if (currentLevel > optLevel) {
            throw new BadRequestException("角色权限不足");
        }
        loginLogService.deleteByUserId(id);
        userService.delete(id);
        return new ResponseEntity(HttpStatus.OK);
    }

    @Log("重置密码")
    @PutMapping(value = "/users/reset")
    @PreAuthorize("hasAnyRole('ADMIN','USER_ALL','USER_RESET')")
    public ResponseEntity reset(@NotBlank String username) {
        return new ResponseEntity(userService.updatePass(username, passwordEncoder.encode(defaultPwd.trim())), HttpStatus.OK);
    }

    /**
     * 修改密码
     *
     * @param user
     * @return
     */
    @PostMapping(value = "/users/updatePass")
    public ResponseEntity updatePass(@RequestBody UserPassVo user) {
        UserDetails userDetails = SecurityUtils.getUserDetails();
        // 密码解密
        RSA rsa = new RSA(privateKey, null);
        String oldPass = new String(rsa.decrypt(user.getOldPass(), KeyType.PrivateKey));
        String newPass = new String(rsa.decrypt(user.getNewPass(), KeyType.PrivateKey));
        if (!passwordEncoder.matches(oldPass, userDetails.getPassword())) {
            throw new BadRequestException("修改失败，旧密码错误");
        }
        if (passwordEncoder.matches(newPass, userDetails.getPassword())) {
            throw new BadRequestException("新密码不能与旧密码相同");
        }
        userService.updatePass(userDetails.getUsername(), passwordEncoder.encode(newPass));
        return new ResponseEntity(HttpStatus.OK);
    }

    /**
     * 管理员修改用户密码
     *
     * @param user
     * @return
     */
    @PostMapping(value = "/users/updateUserPass")
    public ResponseEntity updateUserPass(@RequestBody UserPassVo user) {
        // 密码解密
        RSA rsa = new RSA(privateKey, null);
        String newPass = new String(rsa.decrypt(user.getNewPass(), KeyType.PrivateKey));
        userService.updatePass(user.getUserName(), passwordEncoder.encode(newPass));
        return new ResponseEntity(HttpStatus.OK);
    }

    /**
     * 修改邮箱
     *
     * @param user
     * @param user
     * @return
     */
    @Log("修改邮箱")
    @PostMapping(value = "/users/updateEmail/{code}")
    public ResponseEntity updateEmail(@PathVariable String code, @RequestBody SysUser user) {
        UserDetails userDetails = SecurityUtils.getUserDetails();
        if (!userDetails.getPassword().equals(EncryptUtils.encryptPassword(user.getPassword()))) {
            throw new BadRequestException("密码错误");
        }
        userService.updateEmail(userDetails.getUsername(), user.getEmail());
        return new ResponseEntity(HttpStatus.OK);
    }

    /**
     * 如果当前用户的角色级别低于创建用户的角色级别，则抛出权限不足的错误
     *
     * @param resources
     */
    private void checkLevel(SysUser resources) {
        Integer currentLevel = Collections.min(roleService.findByUsers_Id(SecurityUtils.getUserId()).stream().map(RoleSmallDTO::getLevel).collect(Collectors.toList()));
        Integer optLevel = roleService.findByRoles(resources.getRoles());
        if (currentLevel > optLevel) {
            throw new BadRequestException("角色权限不足");
        }
    }

    @ApiOperation("修改头像")
    @PostMapping(value = "/users/updateAvatar")
    public ResponseEntity updateAvatar(@RequestParam MultipartFile file) {
        userService.updateAvatar(file);
        return new ResponseEntity(HttpStatus.OK);
    }

    @ApiOperation("修改头像")
    @GetMapping(value = "/users/updateAvatarV2")
    public ResponseEntity updateAvatarV2(@RequestParam String url) {
        userService.updateAvatarV2(url);
        return new ResponseEntity(HttpStatus.OK);
    }

    @ApiOperation("获取穿梭框用户数据")
    @GetMapping(value = "/users/transfer")
    public ResponseEntity getTransferUsers(UserQueryCriteria criteria) {
        Set<String> deptSet = new HashSet<>();
        Set<String> result = new HashSet<>();
        if (!ObjectUtils.isEmpty(criteria.getDeptId())) {
            deptSet.add(criteria.getDeptId());
            result.addAll(deptSet);
            criteria.setDeptIds(result);
        }
        return new ResponseEntity(userService.findTransferUsers(criteria), HttpStatus.OK);
    }

    /***
     * description:导入部门用户
     * @param:  * @param deptId
     * @param file
     * @date: 2023-07-24
     * @return: org.springframework.http.ResponseEntity
     * @version v1.0
     * @author:wei_zhang(xiao)
     */
    @ApiOperation(value = "导入部门用户")
    @PostMapping("/importUser")
    public ResponseEntity importUser(@RequestParam @ApiParam("题库id") String deptId,
                                      @RequestParam @ApiParam(value = "导入用户模板文件", required = true) MultipartFile file) {
        // 默认密码
        String passWord= passwordEncoder.encode(defaultPwd.trim());
        userService.userImport(deptId,file, passWord);
        return new ResponseEntity(true, HttpStatus.OK);
    }

    @ApiOperation(value = "下载用户导入模版")
    @AnonymousAccess
    @GetMapping("/downLoadUserTel")
    public void downLoadUserTel(HttpServletResponse response) {
        userService.downLoadUserTel(response);
    }

}
